package com.example.video.controller;

import com.baomidou.mybatisplus.extension.toolkit.Db;
import com.example.video.Enum.Language;
import com.example.video.Enum.videoStatus;
import com.example.video.common.Result;
import com.example.video.entity.*;
import com.example.video.service.*;
import com.example.video.util.HHdata;
import com.example.video.util.RoleUtils;
import com.example.video.util.laixiOperate.Operate;
import com.fasterxml.jackson.databind.JsonNode;
import com.example.video.util.MD5Utils;
import com.example.video.util.queue.DownQueueManager;
import com.example.video.util.scheduled.DynamicTaskScheduler;
import com.github.xiaoymin.knife4j.annotations.ApiSupport;
import jakarta.annotation.PostConstruct;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpSession;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;

import org.springframework.web.servlet.ModelAndView;

import java.net.URISyntaxException;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @desc 后台页面管理
 */
@Slf4j
@Controller
@RequestMapping("/admin")
public class AdminController {

    @Value("${downLoadPath}")
    private String downLoadPath;
    @Value("${ServerUrl}")
    private String serverUrl;
    @Resource
    private IVideoService videoService;
    @Resource
    private IAccountService accountService;

    @Resource
    private IPlatformService platformService;

    @Resource
    private IOuterAccountService outerAccountService;
    @Resource
    private HHdata hHdata;

    @Resource
    private IUserService userService;

    @Resource
    private DownQueueManager downQueueManager;

    @Resource
    private DynamicTaskScheduler scheduler;

    @Resource
    private Operate laixiOperate;

    @Resource
    private IScheduleService scheduleService;

    @Resource
    private com.example.video.util.translateUtil translateUtil;
    @Resource
    private DynamicTaskScheduler dynamicTaskScheduler;

    @Resource
    private ScheduleController scheduleController;




    @PostConstruct
    public void initialize() {
        List<User> roleList = userService.getAllRoles();
        log.info("AdminCtrl -> initialize ->msg: roleList = "+ roleList.stream().map(User::getRole).toList());
        roleList.forEach(item -> {
            Schedule schedule = scheduleService.getItemByRole(item.getRole());
            if(schedule != null){
                String[] time = schedule.getTime().split(":");
                String hour = time[0];
                String minute = time[1];
                scheduleController.setSchedule(hour, minute, item.getRole());
                log.info("AdminCtrl -> initialize ->msg: hour = "+hour +" minute = "+minute +" role = "+item.getRole());
            }else{
                log.info("AdminCtrl -> initialize ->msg: schedule = "+schedule +"无定时任务！");
            }
        });


    }

    /**
     * 重新执行设备init
     */
    @ResponseBody
    @PostMapping("/device/init")
    public String reInit(@RequestParam("deviceId") String deviceId){
        String result = "失败！";
        try
        {
            result = laixiOperate.deviceInit(deviceId);
        }catch (InterruptedException | URISyntaxException e){
            e.printStackTrace();
        }
        return result;
    }



    @PostMapping("/user/info")
    public Result<String> getUserInfo(Authentication authentication){
        Result<String> rs = new Result<>();
        rs.setCode(0);
        log.info(String.valueOf(authentication));

        log.info("AdminCtrl -> /user/info ->mgs: name = "+authentication.getName());
        rs.setData(authentication.getName());
        return rs;
    }


    @GetMapping("/index")
    public String index(Model model){
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        Collection<? extends GrantedAuthority> authorities = authentication.getAuthorities();
        List<String> roles =  RoleUtils.extractRoles(authorities);
        log.info("adminctr -> index -> msg: "+roles);
        boolean isAdmin = authorities.stream().anyMatch(authority -> authority.getAuthority().equals("ROLE_[ROLE_ADMIN]"));

        model.addAttribute("isAdmin", isAdmin);
        return "admin/index";
    }

    @GetMapping("/login")
    public String login(){
        return "admin/login";
    }

    @GetMapping("/account/index")
    public String account(){
        return "account/index";
    }
    @GetMapping("/user/index")
    public String user(){
        return "user/index";
    }
    @GetMapping("/setting/index")
    public String setting(){
        return "setting/index";
    }

    @GetMapping("/outerAccount/index")
    public String outerAcount(){
        return "outerAccount/index";
    }

    @GetMapping("/video/index")
    public String video(){return "video/index";}
    @GetMapping("/device/index")
    public String websocket(){return "device/index";}

    @PostMapping("/user/logout")
    @ResponseBody
    public Result<String> logout(HttpSession session){
        Result<String> rs = new Result<>();
        session.removeAttribute("user");
        rs.setMsg("退出成功！");
        rs.setData(null);
        rs.setCount(0);
        rs.setCode(0);
        return rs;
    }


    /**
     * 通过访问账户管理的添加页面，将账户信息及设置的目标平台信息显示。
     * @param id
     * @param model
     * @return
     */
    @GetMapping("/account/add")
    public ModelAndView addAccount(Integer id, Model model){
        ModelAndView view = new ModelAndView();
        AdminShowAddAccount showAccount= new AdminShowAddAccount();
        List<AdminShowOuter> outerList = new ArrayList<>();
        if(id == 0){
            showAccount.setAccountId(0);
            showAccount.setLanguage("");
            for (Platform item : platformService.getAll()){
                AdminShowOuter outer = new AdminShowOuter();
                outer.setPlatformId(item.getId());
                outer.setPlatformName(item.getPlatformName());
                outer.setOuterId(0);
                outer.setLanguage("");
                outerList.add(outer);
            }

        }else {
            Account account = accountService.getItem(id);
            showAccount.setAccountId(id);
            showAccount.setUrl(account.getUrl());
            showAccount.setPlatform(account.getPlatform());
            showAccount.setLanguage(account.getLanguage());
            showAccount.setToLanguage(account.getToLanguage());
            for (Platform item : platformService.getAll()){
                AdminShowOuter outer = new AdminShowOuter();

                // 查询outer表，以accountId查找
                List<OuterAccount> outerlist = outerAccountService.getListByAccountId(account.getId());
                // 若outer表有数据，则将这个outer的id赋值给outer
                if(outerlist.size()>0){
                    for (OuterAccount outerItem:outerlist){
                        if( outerItem.getPlatformId().equals(item.getId()) ){
                            outer.setOuterId(outerItem.getId());
                            outer.setUserAccount(outerItem.getUserAccount());
                            outer.setUserPwd(outerItem.getUserPwd());
                            outer.setLanguage(outerItem.getLanguage());
                        }
                    }
                    outer.setPlatformId(item.getId());
                    outer.setPlatformName(item.getPlatformName());
                }else{
                    outer.setPlatformId(item.getId());
                    outer.setPlatformName(item.getPlatformName());
                }

                outerList.add(outer);
            }
        }

        showAccount.setOuters(outerList);
//        log.info("showAccount" + showAccount);
        model.addAttribute("model",showAccount);
        model.addAttribute("platforms", platformService.getAll());
        view.setViewName("account/add");

        return view;
    }

    @GetMapping("/videoLog/index")
    public String videoLog(){
        return "videoLog/index";
    }

    @PostMapping("/login.do")
    @ResponseBody
    public Result<String> loginDo(String username, String password, HttpSession session){
        Result<String> rs = new Result<>();

        if(userService.login(username, MD5Utils.md5(password))){
            session.setAttribute("user", userService.getByName(username));
            rs.setCode(0);
            rs.setMsg("登录成功！");
        }else {
            rs.setCode(-1);
            rs.setMsg("用户名或密码错误！");
        }

        return rs;
    }


    /**
     * 手动更新数据检索。每次从cursor=null或“”开始，直到本次有已存在的视频，否则接着下一次
     * @param id
     * @return
     */
    @ResponseBody
    @PostMapping("/freshCrawlData")
    public Result<String> freshCrawlData(Integer id){
        final Result<String> rs = new Result<>();
        Account account = accountService.getItem(id);

        // 从头开始检索5.22注释
//        final String[] next_cursor = {""};
        // 5.5 注释，无需设置cursor
//        account.setNextCursor(next_cursor[0]);

        // 5.22 新增。由于手动更新数据相对于检查是否有新数据，故从null开始
        if(downQueueManager.addTask(account, null)){
            rs.setMsg("任务已添加到队列");
            rs.setCode(0);
            rs.setCount(0);
            rs.setData(null);
        }else{
            rs.setMsg("任务添加失败，请联系管理员！");
            rs.setCode(-1);
            rs.setCount(0);
            rs.setData(null);
        }

        /*
        * 5.22 注释，重写获取接口，只需要调用downLoadTask，传入account和next_cursor即可。
        *
        rs[0] = hHdata.crawlData(id,account.getUrl(), next_cursor[0]);
        log.info("AdminController -> freshCrawlData -> msg: rs[0] = "+rs[0]);
        next_cursor[0] = rs[0].getData();
        if(next_cursor[0] == null){

        }else{
            Account finalAccount = account;

            // 5.5 修改： 不检索到最后一个cursor，而是对null进行检索，检索完后在addList中保存
            Thread thread = new Thread(new Runnable() {
                @Override
                public void run() {
                    // 线程任务
//                    log.info("AdminController -> freshCrawlData -> msg: account = "+accountService.getItem(id));
                    while( !"".equals(accountService.getItem(id).getNextCursor()) ){
                        // 5.5 注释
//                        finalAccount.setNextCursor(next_cursor[0]);
                        rs[0] = hHdata.crawlData(id, finalAccount.getUrl(), next_cursor[0]);
                        next_cursor[0] = rs[0].getData();
                        if(next_cursor[0] == null){
                            break;
                        }
//                        log.info("AdminController -> freshCrawlData -> msg: while rs[0] = "+rs[0]);
                    }

//                    accountService.save(finalAccount);
                }
            });
            thread.start();
        }
        */

        // 5.5 注释
        /*if(next_cursor[0] != null && rs[0].getCode() != -1){
            accountService.save(account);
        }*/

        return rs;
    }


    /**
     * 重新下载错误视频
     * @param id 资源id
     * @return
     */
    @ResponseBody
    @PostMapping("/reloadErrResource")
    public Result<String> videoLogAdmin(Integer id){
        Result<String> rs = new Result<>();

        Video video = videoService.getItem(id);
        Account account = accountService.getItem(video.getAccountId());
        if(downQueueManager.addTask(account, video.getErrCursor())){
            rs.setMsg("任务已添加到队列");
            rs.setCode(0);
            rs.setCount(0);
            rs.setData(null);
        }else{
            rs.setMsg("任务添加失败，请联系管理员！");
            rs.setCode(-1);
            rs.setCount(0);
            rs.setData(null);
        }

        /*
         5.22 注释，重写获取接口，只需要调用downLoadTask，传入account和next_cursor即可。
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                Result<String> rs = new Result<>();
                Video video = videoService.getItem(id);
                Account account = accountService.getItem(video.getAccountId());
                String err_cursor = video.getErrCursor();
                rs = hHdata.crawlData(account.getId(),account.getUrl(),err_cursor);
                if( !"no_more".equals(rs.getData()) ){
                    hHdata.crawlData(account.getId(),account.getUrl(),rs.getData());
                }

                //log.info(rs);
            }
        });
        thread.start();
         */

        return rs;
    }

    /**
     * 重新下载错误视频
     * @param idList 资源id
     * @return
     */
    @ResponseBody
    @PostMapping("/reloadErrByAccountIdArr")
    public Result<String> reloadErrResourceByIdArr(@RequestBody List<Integer> idList){
//        log.info("AdminController -> reloadErrResourceByIdArr -> msg: list ="+idList);
        Result<String> rs = new Result<>();
        rs.setCode(0);
        rs.setMsg("");
        rs.setData(null);
        rs.setCount(0);

        // 检查是否有异常退出下载的账户，从该账户错误标记开始下载
        List<Account> accounts = accountService.getListByAccountIdArr(idList);
        if(accounts != null){
            for(int i=0; i<accounts.size(); i++)
            {
                if(accounts.get(i).getNextCursor()!=null || !"".equals(accounts.get(i).getNextCursor()))
                {
                    downQueueManager.addTask(accounts.get(i), accounts.get(i).getNextCursor());
                }
            }

        }

        List<Video> videos = videoService.getListByNotDownLoadingAndAccountIdArr(idList);
        Map<String, Video> result = new HashMap<>();
        for (Video video :
                videos) {
            String key = video.getErrCursor() + "-" + video.getAccountId();
            result.put(key, video);
        }
        for (Map.Entry<String, Video> entry : result.entrySet()) {
            Video video = entry.getValue();

            Account account = accountService.getItem(video.getAccountId());

            // 5.22 新增
            downQueueManager.addTask(account, video.getErrCursor());

            /*
            5.22 注释，重写获取接口，只需要调用downLoadTask，传入account和next_cursor即可。
            final String[] err_cursor = {video.getErrCursor()};
//            hHdata.crawlData(account.getId(),account.getUrl(),err_cursor);
            Thread thread = new Thread(new Runnable() {
                @Override
                public void run() {
//                    log.info("AdminController -> reloadErrResourceByIdArr -> msg: err_cursor = "+err_cursor[0]);
                    Result<String> rs = new Result<>();
//                    log.info("AdminController -> reloadErrResourceByIdArr -> msg: accountId = "+account.getId());
                    err_cursor[0] = video.getErrCursor();
                    rs = hHdata.crawlData(account.getId(),account.getUrl(), err_cursor[0]);
                    if( !"no_more".equals(rs.getData()) ){
                        hHdata.crawlData(account.getId(),account.getUrl(),rs.getData());
                    }
                    //log.info(rs);
                }
            });
            thread.start();
             */
        }
        return rs;
    }


    /**********************
     ******** 操作 *********
     **********************/

    @ResponseBody
    @PostMapping("/cmd")
    public Result<String> cmd(@RequestBody JsonNode json){
        Result<String> rs = new Result<>();
        log.info("adminContorller -> cmd ->msg: "+json.toString());
        if(json.has("cmd") && json.has("name") && json.has("deviceIds"))
        {
            String cmd = json.get("cmd").asText();
            String name = json.get("name").asText();
            // 提取 deviceIds 数组
            List<String> deviceIds = new ArrayList<>();
            JsonNode deviceIdsNode = json.get("deviceIds");
            if (deviceIdsNode.isArray()) {
                for (JsonNode node : deviceIdsNode) {
                    deviceIds.add(node.asText());
                }
            }
            log.info("AdminCtr -> cmd ->msg: cmd = "+cmd);
            log.info("AdminCtr -> cmd ->msg: name = "+name);
            log.info("AdminCtr -> cmd ->msg: deviceIds = "+deviceIds);

            switch (cmd){
                case "excuJs":{
                    log.info("AdminCtr -> cmd ->msg: 进入excuJs");
                    try {
                        rs.setData(laixiOperate.excuJs(deviceIds, name).getData());
                    } catch (URISyntaxException | InterruptedException e) {
                        rs.setCode(-1);
                        rs.setMsg("来喜服务器连接错误！请联系管理员！");
                        return rs;
                    }
                    break;
                }
                default: {
                    log.info("出错！");
                    break;
                }
            }
            rs.setMsg("命令发送成功！");
            rs.setCode(0);
            rs.setCount(0);

        }else{
            rs.setMsg("出错：请检查上传的参数！");
            rs.setCode(-1);
            rs.setCount(0);
            rs.setData(null);
        }
        log.info("AdminCtr -> cmd ->msg: rs = "+rs);
        return rs;
    }

    @ResponseBody
    @PostMapping("/schedule/upload")
    public Result<String> setSchedule(@RequestParam(defaultValue = "0") String hours,
                                      @RequestParam(defaultValue = "0") String minutes){
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        log.info("AdminCtr -> setSchedule ->msg: auth = "+ authentication.getAuthorities());
        log.info("AdminCtr -> setSchedule ->msg: hour = "+hours + ":"+minutes);
        Result<String> rs = new Result<>();
        List<String> formattedRoles = RoleUtils.extractAndFormatRoles(authentication.getAuthorities());
        rs.setMsg("成功！");
        rs.setCode(0);
        rs.setCount(0);
        Schedule schedule = scheduleService.getItemByRole(formattedRoles.get(0));
        if(schedule == null){
            schedule = new Schedule();
            schedule.setRole(formattedRoles.get(0));
            schedule.setTime(hours+":"+minutes);
            scheduleService.save(schedule);
        }else{
            schedule.setTime(hours+":"+minutes);
            scheduleService.updateById(schedule);
        }
        //TODO：任务id修改为使用role
        String result = scheduler.scheduleTask( schedule.getRole(), ()->{
            log.info("scheduleTask -> 定时任务执行中...");
            List<Device> devices = Db.lambdaQuery(Device.class)
                    .eq(Device::getRole, RoleUtils.extractAndFormatRoles(authentication.getAuthorities()).get(0))
                    .list();
            log.info("admin ->/schedule/upload ->msg: 设备id= "+devices);
            List<String> deviceIds = devices.stream()
                    .map(Device::getDeviceId)
                    .collect(Collectors.toList());
            try {
                log.info("admin ->/schedule/upload ->msg: 结果= "+laixiOperate.excuJs(deviceIds,"request"));
            } catch (URISyntaxException | InterruptedException e) {
                log.info("admin ->/schedule/upload ->msg: 来喜服务连接错误！"+e.getMessage());
            }
        }, LocalDateTime.now().withHour(Integer.parseInt(hours)).withMinute(Integer.parseInt(minutes)).withSecond(0));

        rs.setData(result);

        return rs;
    }


    @ResponseBody
    @PostMapping("/get/schedule")
    public Result<String> getSchedule(Authentication authentication){
        log.info("AdminCtr -> getSchedule ->msg: auth = "+ authentication.getAuthorities());
        Result<String> rs = new Result<>();
        if(scheduleService.getItemByRole(RoleUtils.extractAndFormatRoles(authentication.getAuthorities()).get(0)) == null){
            rs.setMsg("无数据！！");
            rs.setCode(0);
            rs.setCount(0);
            rs.setData(null);
        }else{
            rs.setMsg("成功！");
            rs.setCode(0);
            rs.setCount(0);
            rs.setData(scheduleService.getItemByRole(RoleUtils.extractAndFormatRoles(authentication.getAuthorities()).get(0)).getTime());
        }
        log.info("admin ->/get/schedule ->msg: rs.data = "+rs.getData());
        return rs;
    }


    @ResponseBody
    @PostMapping("/change/video/status")
    public Result<String> changeVideoStatus(@RequestBody List<Long> ids){
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        Result<String> result = new Result<>();
        // 获取处理完毕的资源，只进行该账户下的账户
        List<Account> accounts = Db.lambdaQuery(Account.class)
                .select(Account::getId, Account::getLanguage, Account::getToLanguage)
                .eq(Account::getRole, RoleUtils.extractAndFormatRoles(authentication.getAuthorities()).get(0))
                .list();
        // 遍历每个账户
        accounts.forEach(account -> {
            Integer accountId = account.getId();
            String language = Language.getCodeByName(account.getLanguage());
            String toLanguage = Language.getCodeByName(account.getToLanguage());
            // 获取指定ID列表内的处理完毕的视频
            List<Video> list = Db.lambdaQuery(Video.class)
                    .select(Video::getTitle, Video::getId)
                    .eq(Video::getAccountId, accountId)
                    .eq(Video::getStatus, videoStatus.PROCESSED.getStatus())
                    .in(Video::getId, ids) // 新增条件：只选择在ids列表中的视频
                    .list();
            log.info("ScheduledTask -> change ->msg:videoList = " + list);
            // 遍历每个资源
            list.forEach(video -> {

                log.info("ScheduledTask -> change ->msg:video = " + video);
                Result<String> rs = translateUtil.getTransResult(video.getTitle(), language, toLanguage);


                if(rs.getCode() == 0){
                    log.info("ScheduledTask -> change ->msg:翻译成功！翻译结果 = " + rs.getData());
                    // 修改视频状态
                    Db.lambdaUpdate(Video.class)
                            .eq(Video::getId, video.getId())
                            .set(Video::getStatus, videoStatus.UPLOADABLE.getStatus())
                            .set(Video::getTranslateTitle, rs.getData())
                            .update();
                }else{
                    log.info("ScheduledTask -> change ->msg:此文本翻译出错！ = " + video.getTitle());
                }

            });
        });
        result.setMsg("成功！");
        result.setCode(0);
        result.setData(null);


        return result;
    }





}
